# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: jaewon

import datetime
from collections import namedtuple

from coin.base.datetime_util import to_datetime


def datetime_from_poslog(line):
  try:
    if line[0] != '*':
      return None
    # * 2019-02-11 03:16:00.387037
    # hate it, but fastest..
    dtpart = line[2:29]
    if not (1900 <= int(dtpart[:4]) <= 2100):
      return None
    marker = datetime.datetime(int(dtpart[:4]),
                               int(dtpart[5:7]),
                               int(dtpart[8:10]),
                               int(dtpart[11:13]),
                               int(dtpart[14:16]),
                               int(dtpart[17:19]),
                               int(dtpart[20:26]))
    return marker
  except Exception:
    return None


def datetime_from_glog(line, year):
  try:
    if (line[0] not in ['E', 'W', 'I'] or not (1 <= int(line[1:3]) <= 12)):
      return None

    # I0125 14:59:56.029106
    # hate it, but fastest..
    dtpart = line[1:21]
    marker = datetime.datetime(year,
                               int(dtpart[0:2]),
                               int(dtpart[2:4]),
                               int(dtpart[5:7]),
                               int(dtpart[8:10]),
                               int(dtpart[11:13]),
                               int(dtpart[14:20]))
    return marker
  except Exception:
    return None


def _extract_datetime_1(line):
  timestamp_format = '%Y-%m-%d %H:%M:%S,%f'  # Fucking european style
  tokens = line.split()
  try:
    dt = datetime.datetime.strptime('%s %s' % (tokens[1], tokens[2]), timestamp_format)
    return dt
  except (ValueError, IndexError):
    return None


def _extract_datetime_2(line):
  timestamp_format = '%m%d %H:%M:%S.%f'
  tokens = line.split()
  try:
    now = datetime.datetime.now()
    dt = (datetime.datetime.strptime('%s %s' % (tokens[0][1:], tokens[1]),
                                     timestamp_format).replace(year=now.year))
    if dt > now:
      dt = dt.replace(year=now.year - 1)
    return dt
  except (ValueError, IndexError):
    return None


def extract_datetime(line):
  now = datetime.datetime.now()
  dt = datetime_from_glog(line, now.year)
  if dt is not None:
    return dt
  return datetime_from_poslog(line)


def extract_datetime_slow(line):
  dt = _extract_datetime_1(line)
  if dt is not None:
    return dt
  return _extract_datetime_2(line)


def side_from_sign(signed):
  if int(signed) == 1:
    return 'BUY'
  elif int(signed) == -1:
    return 'SELL'
  else:
    return 'UNKNOWN'


def side_from_str(side_str):
  if 'BUY' in side_str:
    return 'BUY'
  elif 'SELL' in side_str:
    return 'SELL'
  else:
    return 'UNKNOWN'


LogFill = namedtuple('LogFill',
                     ['timestamp', 'exchange', 'symbol', 'side', 'price', 'qty', 'notional_amt'])


def parse_fill_dump(line):
  tokens = line.split(',')
  if len(tokens) != 12 or tokens[0] != '"FILL_DUMP"':
    return None

  # TODO(inkyu): Consider bitfinex
  timestamp = to_datetime(int(tokens[1]))
  exchange = str(tokens[3]).strip('"')
  symbol = str(tokens[4])
  side = side_from_sign(tokens[5])
  price = float(tokens[6])
  qty = float(tokens[7])

  if exchange == 'OkexFutures':
    notional_amt = qty * (100 if 'BTC-USD' in symbol else 10)
  elif exchange == 'Bitmex':
    notional_amt = qty
  else:
    notional_amt = qty * price

  exchange.strip
  return LogFill(timestamp=timestamp,
                 exchange=exchange,
                 symbol=symbol,
                 side=side,
                 price=price,
                 qty=qty,
                 notional_amt=notional_amt)


def parse_fill_log(line):
  tokens = line.split()

  # INFO 2018-06-13 18:30:10,472 Bitflyer order_gateway.py:275] FILL FX_BTC_JPY SELL 1.000000 @ 721370.000000
  # I0725 08:11:47.967512 139756067235648 order_gateway.py:287] FILL FX_BTC_JPY  BUY 1.400000 @ 965684.000000
  if (len(tokens) >= 6 and 'FILL' in tokens and 'FX_BTC_JPY' in tokens):
    base_idx = tokens.index('FILL')
    timestamp = extract_datetime(line)
    side = side_from_str(tokens[base_idx + 2])
    price = float(tokens[base_idx + 5])
    qty = float(tokens[base_idx + 3])
    notional_amt = price * qty
    return LogFill(timestamp=timestamp,
                   exchange='Bitflyer',
                   symbol='FX_BTC_JPY',
                   side=side,
                   price=price,
                   qty=qty,
                   notional_amt=notional_amt)

  return None
